#include "Price.h"

Price::Price(string fileName) {
	/* 'fileName' may contain a type, example: "MYHOTEL.DTA".
	 * In such a case, the string is stripped to only contain
	 * "MYHOTEL". "MY.HOTEL.DTA" will be stripped to "MY.HOTEL".
	 */
	int typeIdx = -1;
	for (unsigned i = 0; i < fileName.length(); i++) {
		if (fileName[i] == '.') {
			typeIdx = i;
		}
	}
	
	if (typeIdx != -1) {
		fileName = fileName.substr(0, typeIdx);
	}
	
	ifstream file((fileName + ".prs").c_str());
	if (!file.is_open()) {
		/* Terminate the program if the file cannot be found. */
		stringstream ss;
		ss << "Failed to open file \"" << fileName << ".prs\"!";
		Critical(ss.str());
	}
	
	/* Null out standard prices */
	for (unsigned i = 0; i < 3; i++) {
		stdWeek[i] = stdWeekend[i] = 0;
	}
	intervals = new List(FIFO);
	
	/* Read from file */
	while (file.good()) {
		while (file.peek() == '\t') {
			string dump;
			getline(file, dump);
		}
		
		string word;
		file >> word;
		
		if (word == "standard") {
			readStandard(file);
		} else {

			// If not standard
			Date start = atoi(word.c_str());
			file >> word; 	file.ignore();
			Date end = atoi(word.c_str());
			
			// As long the date is incorrect
			if (DateVerify::Verify(start) != DateVerify::ERR_NONE
			||  DateVerify::Verify(end)   != DateVerify::ERR_NONE) {
				stringstream ss;
				ss  <<"Dates in PRS-file are invalid: " <<start <<" - " <<end;
				
				Warning(ss.str());
				getline(file, word);
			} else {

				int num = 0;
				file >> num;   file.ignore();
				
				readInterval(file, start, end, num);
			}
		}
	}
	
	return;
	
	string s[3] = {"Single", "Double", "Suite"};
	
	// Print the price for the week
	printf("Week prices:\n");
	for (unsigned i = 0; i < 3; i++) {
		printf("\t%s - %i\n", s[i].c_str(), stdWeek[i]);
	}
	
	// Print the price for the weekend
	printf("Weekend prices:\n");
	for (unsigned i = 0; i < 3; i++) {
		printf("\t%s - %i\n", s[i].c_str(), stdWeekend[i]);
	}
	
	// Print spesial prices
	for (unsigned i = 0; i < intervals->no_of_elements(); i++) {
		Interval *in = (Interval*)intervals->remove();
		intervals->add(in);
		
		printf("interval: %s  -  %s\n",
			   dateToString(in->start).c_str(),
			   dateToString(in->end).c_str()
		);
		
		printf("\tWeek:\n");
		for (unsigned j = 0; j < 3; j++) {
			printf("\t\t%s - %i\n", s[j].c_str(), in->week[j]);
		}
		
		printf("\tWeekend:\n");
		for (unsigned j = 0; j < 3; j++) {
			printf("\t\t%s - %i\n", s[j].c_str(), in->weekend[j]);
		}
	}
}

Price::~Price() {
	delete intervals;
}

int Price::getPrice(Date date, Room::RoomType type) {
	int price = specialPrice(date, type);
	if (price != 0) {
		return price;
	}
	
	return defaultPrice(date, type);
}

int Price::defaultPrice(Date date, Room::RoomType type) {
	if (isWeekend(date)) {
		return stdWeekend[type];
	} else {
		return stdWeek[type];
	}
}

int Price::specialPrice(Date date, Room::RoomType type) {
	/* If any two intervals overlap, use the cheapest alternative */
	int bestPrice = INT_MAX;
	bool weekend = isWeekend(date);
	
	// Going through all elements in the intervals list
	for (unsigned i = 0; i < intervals->no_of_elements(); i++) {
		Interval *inter = (Interval*)intervals->remove();
		intervals->add(inter);
		
		// If the date is correct
		if (date >= inter->start && date <= inter->end) {
			int curPrice = 0;

			// It is weekend
			if (weekend) {
				curPrice = inter->weekend[type];
			} else {
				curPrice = inter->week[type];
			}
			
			// Is curPrice less than bestPrice?
			if (curPrice != 0 && curPrice < bestPrice) {
				bestPrice = curPrice;
			}
		}
	}
	
	/* Return 0 if bestPrice is INT_MAX */
	return (bestPrice == INT_MAX) ? 0 : bestPrice;
}


void Price::readStandard(ifstream &file) {
	string type;
	file >> type;
	file.ignore();
	
	int *prices = NULL;
	
	if (type == "week") {
		prices = stdWeek;
	} else if (type == "weekend") {
		prices = stdWeekend;
	} else {
		stringstream ss;
		ss << "Invalid standard descriptor: " << type;
		Error(ss.str());
		return;
	}
	
	readSinglePrice(file, prices);
	readSinglePrice(file, prices);
	readSinglePrice(file, prices);
}

void Price::readInterval(ifstream &file, Date start, Date end, int num) {
	Interval *interval = new Interval;
	intervals->add(interval);
	
	interval->start = start;
	interval->end = end;
	
	for (unsigned i = 0; i < num; i++) {
		readSinglePrice(file, interval);
	}
}

void Price::readSinglePrice(ifstream &file, int *prices) {
	string type;
	file >> type;
	file.ignore();
	
	int *price = NULL;
	
	// Check to read to the right slot
	if (type == "single") {
		price = &prices[0];
	} else if (type == "double") {
		price = &prices[1];
	} else if (type == "suite") {
		price = &prices[2];
	} else {
		stringstream ss;
		ss << "Invalid category descriptor in PRS-file: " << type;
		Error(ss.str());
		return;
	}
	
	file >> *price;
	file.ignore();
}

void Price::readSinglePrice(ifstream &file, Price::Interval *interval) {
	string roomType;
	string priceType;
	file >> roomType; 	file.ignore();
	file >> priceType;	file.ignore();
	
	int priceIdx = 0;
	
	/* Determine the room type */
	if (roomType == "single") {
		priceIdx = 0;
	} else if (roomType == "double") {
		priceIdx = 1;
	} else if (roomType == "suite") {
		priceIdx = 2;
	} else {
		stringstream ss;
		ss << "Invalid category descriptor in PRS-file: " << roomType;
		Error(ss.str());
		return;
	}
	
	/* Determine the price array and read into it */
	if (priceType == "week") {
		file >> interval->week[priceIdx];
	} else if (priceType == "end") {
		file >> interval->weekend[priceIdx];
	} else if (priceType == "all") {
		file >> interval->week[priceIdx];
		interval->weekend[priceIdx] = interval->week[priceIdx];
	} else {
		stringstream ss;
		ss << "Invalid period descriptor in PRS-file: " << priceType;
		Error(ss.str());
		return;
	}
	
	file.ignore();
}


bool Price::isWeekend(Date date) {
	return (Singletons::timer->ukedagsnr(date) >= 5);
}





